package repository

import (
	"context"
	"database/sql"
	"fmt"
	"strconv"
	"strings"

	"mall/common/enumx"
	"mall/common/modelx"
	"mall/service/blog/model"

	"github.com/gosimple/slug"
	"github.com/volatiletech/sqlboiler/v4/boil"
	"github.com/volatiletech/sqlboiler/v4/queries"
	"github.com/volatiletech/sqlboiler/v4/queries/qm"
	"github.com/zeromicro/go-zero/core/stores/cache"
)

type (
	// BlogBookRepository is an interface to be customized, add more methods here,
	// and implement the added methods in customBlogBookRepository.
	BlogBookRepository interface {
		Conn() error
		FindOne(
			ctx context.Context,
			id int64,
			cols []string,
		) (*model.BlogKnowledgeBasis, error)
		GetList(
			ctx context.Context,
			cols model.M,
			withCount int,
			filter map[string]map[string][]any,
		) ([]*model.BlogKnowledgeBasis, int64, error)
		Insert(
			ctx context.Context,
			entry *model.BlogKnowledgeBasis,
			detail *model.BlogKnowledgeBaseDetail,
			meta []*model.BlogKnowledgeBaseMetum,
			extra *model.BlogExtra,
		) error
		Update(
			ctx context.Context,
			entry *model.BlogKnowledgeBasis,
			detail *model.BlogKnowledgeBaseDetail,
			meta []*model.BlogKnowledgeBaseMetum,
			extra *model.BlogExtra,
		) (int64, error)
		UpdateBatch(ctx context.Context, ids []int64, cols model.M) (int64, error) //////
		ForceDeleteBatch(ctx context.Context, ids []int64) (int64, error)          //////
		GetDetail(
			ctx context.Context,
			cols model.M,
			withCount int,
			filter map[string]map[string][]any,
		) ([]*model.BlogKnowledgeBaseDetail, int64, error)
		GetMeta(
			ctx context.Context,
			cols model.M,
			withCount int,
			filter map[string]map[string][]any,
		) ([]*model.BlogKnowledgeBaseMetum, int64, error)
		GetMedia(
			ctx context.Context,
			cols model.M,
			withCount int,
			filter map[string]map[string][]any,
		) ([]*model.BlogAttachmentRelationship, int64, error)
		InsertMedia(ctx context.Context, media []*model.BlogAttachmentRelationship) error //////
		GetRelationshipList(
			ctx context.Context,
			cols model.M,
			withCount int,
			filter map[string]map[string][]any,
		) ([]*model.BlogKnowledgeBaseRelationship, int64, error)
		IncreaseMeta(ctx context.Context, ids []int64, metaKey string, step int) error //////
		DecreaseMeta(ctx context.Context, ids []int64, metaKey string, step int) error //////
		InsertMeta(ctx context.Context, meta []*model.BlogKnowledgeBaseMetum) error    //////
		UpdateMetum(ctx context.Context, id uint64, cols model.M) (int64, error)
	}

	customBlogBookRepository struct {
		cacheConf  cache.CacheConf
		dataSource string

		mysqlConn *sql.DB
	}
)

// NewBlogBookRepository returns a repository for the database table.
func NewBlogBookRepository(dataSource string, cacheConf cache.CacheConf) BlogBookRepository {
	return &customBlogBookRepository{
		cacheConf:  cacheConf,
		dataSource: dataSource,
	}
}

func (r *customBlogBookRepository) Conn() error {
	if r.mysqlConn == nil {
		mysqlConn, err := modelx.NewMysqlConn(r.dataSource)
		if err != nil {
			return err
		}

		r.mysqlConn = mysqlConn
	}

	return nil
}

func (r *customBlogBookRepository) FindOne(
	ctx context.Context,
	id int64,
	cols []string,
) (entry *model.BlogKnowledgeBasis, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	entry, err = model.FindBlogKnowledgeBasis(ctx, r.mysqlConn, uint64(id), cols...)
	if err == sql.ErrNoRows {
		return nil, model.ErrNotFound
	}
	return
}

func (r *customBlogBookRepository) GetList(
	ctx context.Context,
	cols model.M,
	withCount int,
	filter map[string]map[string][]any,
) (list []*model.BlogKnowledgeBasis, count int64, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	var mods []qm.QueryMod
	var page int
	var pageSize int
	var offset int
	var limit int
	var selectCol string
	for k, v := range cols {
		switch k {
		case "page":
			if val, ok := v.(int64); ok && val > 1 {
				page = int(val)
			}
		case "pageSize":
			if val, ok := v.(int64); ok && val > 0 {
				pageSize = int(val)
			}
		case "offset":
			if val, ok := v.(int32); ok && val > 0 {
				offset = int(val)
			}
		case "limit":
			if val, ok := v.(int32); ok && val > 0 {
				limit = int(val)
			}
		case "orderBy":
			if val, ok := v.(string); ok && val != "" {
				mods = append(mods, qm.OrderBy(val))
			}
		case "select":
			if val, ok := v.(string); ok && val != "" {
				selectCol = val
			}
		case "asPreview":
			if val, ok := v.(string); ok && val == "" { // 不是预览，必须是已发布
				mods = append(mods, model.BlogKnowledgeBasisWhere.PostStatus.EQ(uint16(enumx.PostStatusPublish)))
			}
		case "search":
			if val, ok := v.(string); ok && val != "" { // 搜索
				likeVal := fmt.Sprintf("%%%s%%", val)
				mods = append(mods, qm.Where(fmt.Sprintf(
					"(%s LIKE ? OR %s LIKE ?)",
					model.BlogKnowledgeBasisColumns.PostTitle,
					model.BlogKnowledgeBasisColumns.PostName), likeVal, likeVal))
			}
		}
	}

	if filter != nil {
		for key, opMap := range filter {
			switch key {
			case model.BlogKnowledgeBasisColumns.ID:
				mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBasisColumns.ID, opMap)...)
			case model.BlogKnowledgeBasisColumns.PostAuthorID:
				mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBasisColumns.PostAuthorID, opMap)...)
			case model.BlogKnowledgeBasisColumns.PostParentID:
				mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBasisColumns.PostParentID, opMap)...)
			case model.BlogKnowledgeBasisColumns.PostTitle:
				mods = append(mods, modelx.GetStringMods(model.BlogKnowledgeBasisColumns.PostTitle, opMap)...)
			case model.BlogKnowledgeBasisColumns.PostExcerpt:
				mods = append(mods, modelx.GetStringMods(model.BlogKnowledgeBasisColumns.PostExcerpt, opMap)...)
			case model.BlogKnowledgeBasisColumns.PostStatus:
				mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBasisColumns.PostStatus, opMap)...)
			case model.BlogKnowledgeBasisColumns.CommentStatus:
				mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBasisColumns.CommentStatus, opMap)...)
			case model.BlogKnowledgeBasisColumns.PostName:
				mods = append(mods, modelx.GetStringMods(model.BlogKnowledgeBasisColumns.PostName, opMap)...)
			case model.BlogKnowledgeBasisColumns.GUID:
				for op, vals := range opMap {
					if len(vals) > 0 {
						switch op {
						case "equalTo":
							var sa []string
							for _, val := range vals {
								if s, ok := val.(string); ok {
									sa = append(sa, s)
								}
							}
							var guid string
							guid = strings.TrimPrefix(strings.Join(sa, "/"), "knowledge-base/")
							guid = fmt.Sprintf("/knowledge-base/%s/", guid)
							mods = append(mods, model.BlogKnowledgeBasisWhere.GUID.EQ(guid))
						}
					}
				}
			}
		}
	}

	if withCount >= 0 {
		if withCount >= 2 { // 2 or 3（不管前一页）
			var nextCount int64
			var previousCount int64
			subMods := make([]qm.QueryMod, len(mods), len(mods)+3)
			copy(subMods, mods)
			subMods = append(subMods, qm.Limit(1))
			subMods = append(subMods, qm.Select(model.BlogKnowledgeBasisColumns.ID))

			if withCount != 3 && offset >= 1 { // 前一页
				subMods = append(subMods, qm.Offset(offset-1))
				previousList, previousErr := model.BlogKnowledgeBases(subMods...).All(ctx, r.mysqlConn)
				if previousErr != nil {
					err = previousErr
					return
				}
				if len(previousList) > 0 {
					previousCount = 1
				}
			}
			if limit > 0 { // 后一页
				subMods = append(subMods, qm.Offset(offset+limit))
				nextList, nextErr := model.BlogKnowledgeBases(subMods...).All(ctx, r.mysqlConn)
				if nextErr != nil {
					err = nextErr
					return
				}
				if len(nextList) > 0 {
					nextCount = 1
				}
			}

			count = previousCount + nextCount*2
		} else { // 1 or 0
			count, err = model.BlogKnowledgeBases(mods...).Count(ctx, r.mysqlConn)
			if err != nil {
				return
			}

			if withCount == 0 {
				return
			}
		}
	}

	if pageSize > 0 {
		if page > 1 {
			mods = append(mods, qm.Offset(pageSize*(page-1)))
		}
		mods = append(mods, qm.Limit(pageSize))
	} else if limit > 0 || offset > 0 {
		if limit > 0 {
			mods = append(mods, qm.Limit(limit))
		}
		if offset > 0 {
			mods = append(mods, qm.Offset(offset))
		}
	}

	var columns []string
	if selectCol != "" {
		if selectCol != "," {
			columns = strings.Split(selectCol, ",")
		}
		columns = append(columns, model.BlogKnowledgeBasisColumns.ID)
	}
	if len(columns) > 0 {
		mods = append(mods, qm.Select(columns...))
	}

	list, err = model.BlogKnowledgeBases(mods...).All(ctx, r.mysqlConn)
	return
}

func (r *customBlogBookRepository) Insert(
	ctx context.Context,
	entry *model.BlogKnowledgeBasis,
	detail *model.BlogKnowledgeBaseDetail,
	meta []*model.BlogKnowledgeBaseMetum,
	extra *model.BlogExtra,
) error {
	if err := r.Conn(); err != nil {
		return err
	}

	tx, err := r.mysqlConn.BeginTx(ctx, nil)
	if err != nil {
		return err
	}

	if extra.Uri != "" {
		entry.GUID = extra.Uri
	} else if extra.UriTemplate != "" {
		slug.Lowercase = false
		var parentSlug string
		if extra.ParentId > 0 {
			parent, parentErr := model.FindBlogKnowledgeBasis(ctx, tx, uint64(extra.ParentId), model.BlogKnowledgeBasisColumns.PostName)
			if parentErr != nil {
				tx.Rollback()
				return parentErr
			}

			if parent.PostName != "" {
				parentSlug = fmt.Sprintf("%s/", slug.Make(parent.PostName))
			}
		}

		entry.GUID = fmt.Sprintf("%s%s%s%s/", extra.UriTemplate, parentSlug, slug.Make(entry.PostName), extra.Version)
	}

	err = entry.Insert(ctx, tx, boil.Infer())
	if err != nil {
		tx.Rollback()
		return err
	}

	entryId := entry.ID
	detail.KnowledgeBaseID = entryId
	err = detail.Insert(ctx, tx, boil.Infer())
	if err != nil {
		tx.Rollback()
		return err
	}

	if len(meta) > 0 {
		for _, m := range meta {
			m.KnowledgeBaseID = entryId
			err = m.Insert(ctx, tx, boil.Infer())
			if err != nil {
				tx.Rollback()
				return err
			}
		}
	}

	objectType := uint16(enumx.PostTypeKnowledgeBase)
	if len(extra.CategoryIds) > 0 {
		for _, cid := range extra.CategoryIds {
			var relationShip model.BlogTermRelationship
			relationShip.ObjectID = entryId
			relationShip.ObjectType = objectType
			relationShip.TermID = uint64(cid)
			err = relationShip.Insert(ctx, tx, boil.Infer())
			if err != nil {
				tx.Rollback()
				return err
			}
		}
	}
	if len(extra.TagIds) > 0 {
		for _, tid := range extra.TagIds {
			var relationShip model.BlogTermRelationship
			relationShip.ObjectID = entryId
			relationShip.ObjectType = objectType
			relationShip.TermID = uint64(tid)
			err = relationShip.Insert(ctx, tx, boil.Infer())
			if err != nil {
				tx.Rollback()
				return err
			}
		}
	}
	if extra.SectionId > 0 {
		var relationShip model.BlogTermRelationship
		relationShip.ObjectID = entryId
		relationShip.ObjectType = objectType
		relationShip.TermID = uint64(extra.SectionId)
		relationShip.TermOrder = entry.MenuOrder
		err = relationShip.Insert(ctx, tx, boil.Infer())
		if err != nil {
			tx.Rollback()
			return err
		}
	}
	if len(extra.Media) > 0 {
		for _, m := range extra.Media {
			m.ObjectID = entryId
			m.ObjectType = objectType
			err = m.Insert(ctx, tx, boil.Infer())
			if err != nil {
				tx.Rollback()
				return err
			}
		}
	}
	if len(extra.Relations) > 0 {
		for _, r := range extra.Relations {
			r.FromEntryID = entryId
			err = r.Insert(ctx, tx, boil.Infer())
			if err != nil {
				tx.Rollback()
				return err
			}
		}
	}
	if len(extra.VersionRelations) > 0 {
		for _, r := range extra.VersionRelations {
			r.ToEntryID = entryId
			err = r.Insert(ctx, tx, boil.Infer())
			if err != nil {
				tx.Rollback()
				return err
			}
		}
	}

	tx.Commit()
	return nil
}

func (r *customBlogBookRepository) Update(
	ctx context.Context,
	entry *model.BlogKnowledgeBasis,
	detail *model.BlogKnowledgeBaseDetail,
	meta []*model.BlogKnowledgeBaseMetum,
	extra *model.BlogExtra,
) (int64, error) {
	if err := r.Conn(); err != nil {
		return 0, err
	}

	tx, err := r.mysqlConn.BeginTx(ctx, nil)
	if err != nil {
		return 0, err
	}

	if extra.Uri != "" {
		entry.GUID = extra.Uri
	} else if extra.UriTemplate != "" {
		slug.Lowercase = false
		var parentSlug string
		if extra.ParentId > 0 {
			parent, parentErr := model.FindBlogKnowledgeBasis(ctx, tx, uint64(extra.ParentId), model.BlogKnowledgeBasisColumns.PostName)
			if parentErr != nil {
				tx.Rollback()
				return 0, parentErr
			}

			if parent.PostName != "" {
				parentSlug = fmt.Sprintf("%s/", slug.Make(parent.PostName))
			}
		}

		entry.GUID = fmt.Sprintf("%s%s%s%s/", extra.UriTemplate, parentSlug, slug.Make(entry.PostName), extra.Version)
	}

	entryId, err := entry.Update(ctx, tx, boil.Blacklist(
		model.BlogKnowledgeBasisColumns.PostAuthorID,
		model.BlogKnowledgeBasisColumns.PostParentID,
		model.BlogKnowledgeBasisColumns.CommentCount,
	))
	if err != nil {
		tx.Rollback()
		return 0, err
	}

	eid := entry.ID
	detail.KnowledgeBaseID = eid
	_, err = detail.Update(ctx, tx, boil.Blacklist(
		model.BlogKnowledgeBaseDetailColumns.DetailID,
		model.BlogKnowledgeBaseDetailColumns.KnowledgeBaseID,
	))
	if err != nil {
		tx.Rollback()
		return 0, err
	}

	if len(meta) > 0 {
		for _, m := range meta {
			if m.MetaID > 0 {
				_, err = m.Update(ctx, tx, boil.Blacklist(
					model.BlogKnowledgeBaseMetumColumns.MetaID,
					model.BlogKnowledgeBaseMetumColumns.KnowledgeBaseID,
				))
			} else {
				m.KnowledgeBaseID = eid
				err = m.Insert(ctx, tx, boil.Infer())
			}

			if err != nil {
				tx.Rollback()
				return 0, err
			}
		}
	}

	objectType := uint16(enumx.PostTypeKnowledgeBase)
	if len(extra.Terms) > 0 {
		for _, t := range extra.Terms {
			if t.TermRelationshipID > 0 {
				_, err = t.Update(ctx, tx, boil.Blacklist(
					model.BlogTermRelationshipColumns.TermRelationshipID,
					model.BlogTermRelationshipColumns.ObjectID,
					model.BlogTermRelationshipColumns.ObjectType,
					model.BlogTermRelationshipColumns.TermID,
				))
				if err != nil {
					tx.Rollback()
					return 0, err
				}
			}
		}
	}
	if len(extra.CategoryIds) > 0 {
		for _, cid := range extra.CategoryIds {
			var relationShip model.BlogTermRelationship
			relationShip.ObjectID = eid
			relationShip.ObjectType = objectType
			relationShip.TermID = uint64(cid)
			err = relationShip.Insert(ctx, tx, boil.Infer())
			if err != nil {
				tx.Rollback()
				return 0, err
			}
		}
	}
	if len(extra.TagIds) > 0 {
		for _, tid := range extra.TagIds {
			var relationShip model.BlogTermRelationship
			relationShip.ObjectID = eid
			relationShip.ObjectType = objectType
			relationShip.TermID = uint64(tid)
			err = relationShip.Insert(ctx, tx, boil.Infer())
			if err != nil {
				tx.Rollback()
				return 0, err
			}
		}
	}
	if extra.SectionId > 0 {
		var relationShip model.BlogTermRelationship
		relationShip.ObjectID = eid
		relationShip.ObjectType = objectType
		relationShip.TermID = uint64(extra.SectionId)
		relationShip.TermOrder = entry.MenuOrder
		err = relationShip.Insert(ctx, tx, boil.Infer())
		if err != nil {
			tx.Rollback()
			return 0, err
		}
	}
	if len(extra.Media) > 0 {
		for _, m := range extra.Media {
			if m.AttachmentRelationshipID > 0 {
				_, err = m.Update(ctx, tx, boil.Blacklist(
					model.BlogAttachmentRelationshipColumns.AttachmentRelationshipID,
					model.BlogAttachmentRelationshipColumns.ObjectID,
					model.BlogAttachmentRelationshipColumns.ObjectType,
					model.BlogAttachmentRelationshipColumns.AttachmentID,
				))
			} else {
				m.ObjectID = eid
				m.ObjectType = objectType
				err = m.Insert(ctx, tx, boil.Infer())
			}
			if err != nil {
				tx.Rollback()
				return 0, err
			}
		}
	}
	if len(extra.Relations) > 0 {
		for _, r := range extra.Relations {
			if r.EntryRelationshipID > 0 {
				_, err = r.Update(ctx, tx, boil.Blacklist(
					model.BlogKnowledgeBaseRelationshipColumns.EntryRelationshipID,
					model.BlogKnowledgeBaseRelationshipColumns.FromEntryID,
					model.BlogKnowledgeBaseRelationshipColumns.ToEntryID,
				))
			} else {
				r.FromEntryID = eid
				err = r.Insert(ctx, tx, boil.Infer())
			}
			if err != nil {
				tx.Rollback()
				return 0, err
			}
		}
	}
	if len(extra.DelMetaIds) > 0 {
		ids := make([]any, 0, len(extra.DelMetaIds))
		for _, id := range extra.DelMetaIds {
			ids = append(ids, id)
		}
		var mods []qm.QueryMod
		mods = append(mods, qm.WhereIn(fmt.Sprintf("%s IN ?", model.BlogKnowledgeBaseMetumColumns.MetaID), ids...))
		_, err := model.BlogKnowledgeBaseMeta(mods...).DeleteAll(ctx, tx)
		if err != nil {
			tx.Rollback()
			return 0, err
		}
	}
	if len(extra.DelTermIds) > 0 {
		ids := make([]any, 0, len(extra.DelTermIds))
		for _, id := range extra.DelTermIds {
			ids = append(ids, id)
		}
		var mods []qm.QueryMod
		mods = append(mods, qm.WhereIn(fmt.Sprintf("%s IN ?", model.BlogTermRelationshipColumns.TermRelationshipID), ids...))
		_, err := model.BlogTermRelationships(mods...).DeleteAll(ctx, tx)
		if err != nil {
			tx.Rollback()
			return 0, err
		}
	}
	if len(extra.DelMediaIds) > 0 {
		ids := make([]any, 0, len(extra.DelMediaIds))
		for _, id := range extra.DelMediaIds {
			ids = append(ids, id)
		}
		var mods []qm.QueryMod
		mods = append(mods, qm.WhereIn(fmt.Sprintf("%s IN ?", model.BlogAttachmentRelationshipColumns.AttachmentRelationshipID), ids...))
		_, err := model.BlogAttachmentRelationships(mods...).DeleteAll(ctx, tx)
		if err != nil {
			tx.Rollback()
			return 0, err
		}
	}
	if len(extra.DelRelationIds) > 0 {
		ids := make([]any, 0, len(extra.DelRelationIds))
		for _, id := range extra.DelRelationIds {
			ids = append(ids, id)
		}
		var mods []qm.QueryMod
		mods = append(mods, qm.WhereIn(fmt.Sprintf("%s IN ?", model.BlogKnowledgeBaseRelationshipColumns.EntryRelationshipID), ids...))
		_, err := model.BlogKnowledgeBaseRelationships(mods...).DeleteAll(ctx, tx)
		if err != nil {
			tx.Rollback()
			return 0, err
		}
	}

	tx.Commit()
	return entryId, nil
}

func (r *customBlogBookRepository) UpdateBatch(ctx context.Context, ids []int64, cols model.M) (rowsAff int64, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	var mods []qm.QueryMod
	if len(ids) > 0 {
		values := make([]any, 0, len(ids))
		for _, id := range ids {
			values = append(values, uint64(id))
		}

		mods = append(mods, qm.WhereIn(fmt.Sprintf("%s IN ?", model.BlogKnowledgeBasisColumns.ID), values...))
	}

	rowsAff, err = model.BlogKnowledgeBases(mods...).UpdateAll(ctx, r.mysqlConn, cols)
	return
}

func (r *customBlogBookRepository) ForceDeleteBatch(ctx context.Context, ids []int64) (rowsAff int64, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	tx, err := r.mysqlConn.BeginTx(ctx, nil)
	if err != nil {
		return 0, err
	}

	if len(ids) > 0 {
		var mods []qm.QueryMod
		values := make([]any, 0, len(ids))
		for _, id := range ids {
			values = append(values, uint64(id))
		}
		mods = append(mods, qm.WhereIn(fmt.Sprintf("%s IN ?", model.BlogKnowledgeBasisColumns.ID), values...))
		rowsAff, err = model.BlogKnowledgeBases(mods...).DeleteAll(ctx, tx)
		if err != nil {
			tx.Rollback()
			return 0, err
		}

		mod := qm.WhereIn(fmt.Sprintf("%s IN ?", model.BlogKnowledgeBaseDetailColumns.KnowledgeBaseID), values...)
		_, err = model.BlogKnowledgeBaseDetails(mod).DeleteAll(ctx, tx)
		if err != nil {
			tx.Rollback()
			return 0, err
		}

		mod = qm.WhereIn(fmt.Sprintf("%s IN ?", model.BlogKnowledgeBaseMetumColumns.KnowledgeBaseID), values...)
		_, err = model.BlogKnowledgeBaseMeta(mod).DeleteAll(ctx, tx)
		if err != nil {
			tx.Rollback()
			return 0, err
		}

		var termRelationshipMods []qm.QueryMod
		termRelationshipMods = append(
			termRelationshipMods,
			qm.WhereIn(fmt.Sprintf("%s IN ?", model.BlogTermRelationshipColumns.ObjectID), values...),
		)
		termRelationshipMods = append(
			termRelationshipMods,
			model.BlogTermRelationshipWhere.ObjectType.EQ(uint16(enumx.PostTypeKnowledgeBase)),
		)
		_, err = model.BlogTermRelationships(termRelationshipMods...).DeleteAll(ctx, tx)
		if err != nil {
			tx.Rollback()
			return 0, err
		}

		var attachmentRelationshipMods []qm.QueryMod
		attachmentRelationshipMods = append(
			attachmentRelationshipMods,
			qm.WhereIn(fmt.Sprintf("%s IN ?", model.BlogAttachmentRelationshipColumns.ObjectID), values...),
		)
		attachmentRelationshipMods = append(
			attachmentRelationshipMods,
			model.BlogAttachmentRelationshipWhere.ObjectType.EQ(uint16(enumx.PostTypeKnowledgeBase)),
		)
		_, err = model.BlogAttachmentRelationships(attachmentRelationshipMods...).DeleteAll(ctx, tx)
		if err != nil {
			tx.Rollback()
			return 0, err
		}

		mod = qm.WhereIn(fmt.Sprintf("%s IN ?", model.BlogKnowledgeBaseRelationshipColumns.FromEntryID), values...)
		_, err = model.BlogKnowledgeBaseRelationships(mod).DeleteAll(ctx, tx)
		if err != nil {
			tx.Rollback()
			return 0, err
		}

		mod = qm.WhereIn(fmt.Sprintf("%s IN ?", model.BlogKnowledgeBaseRelationshipColumns.ToEntryID), values...)
		_, err = model.BlogKnowledgeBaseRelationships(mod).DeleteAll(ctx, tx)
		if err != nil {
			tx.Rollback()
			return 0, err
		}
	}

	tx.Commit()
	return
}

func (r *customBlogBookRepository) GetDetail(
	ctx context.Context,
	cols model.M,
	withCount int,
	filter map[string]map[string][]any,
) (list []*model.BlogKnowledgeBaseDetail, count int64, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	var mods []qm.QueryMod
	var page int
	var pageSize int
	var selectCol string
	for k, v := range cols {
		switch k {
		case "page":
			if val, ok := v.(int64); ok && val > 1 {
				page = int(val)
			}
		case "pageSize":
			if val, ok := v.(int64); ok && val > 0 {
				pageSize = int(val)
			}
		case "orderBy":
			if val, ok := v.(string); ok && val != "" {
				mods = append(mods, qm.OrderBy(val))
			}
		case "select":
			if val, ok := v.(string); ok && val != "" {
				selectCol = val
			}
		}
	}

	if filter != nil {
		for key, opMap := range filter {
			switch key {
			case model.BlogKnowledgeBaseDetailColumns.DetailID:
				mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBaseDetailColumns.DetailID, opMap)...)
			case model.BlogKnowledgeBaseDetailColumns.KnowledgeBaseID:
				mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBaseDetailColumns.KnowledgeBaseID, opMap)...)
			}
		}
	}

	if withCount >= 0 {
		count, err = model.BlogKnowledgeBaseDetails(mods...).Count(ctx, r.mysqlConn)
		if err != nil {
			return
		}

		if withCount == 0 {
			return
		}
	}

	if pageSize > 0 {
		if page > 1 {
			mods = append(mods, qm.Offset(pageSize*(page-1)))
		}
		mods = append(mods, qm.Limit(pageSize))
	}

	var columns []string
	if selectCol != "" {
		if selectCol != "," {
			columns = strings.Split(selectCol, ",")
		}
		columns = append(columns, model.BlogKnowledgeBaseDetailColumns.DetailID)
		columns = append(columns, model.BlogKnowledgeBaseDetailColumns.KnowledgeBaseID)
	}
	if len(columns) > 0 {
		mods = append(mods, qm.Select(columns...))
	}

	list, err = model.BlogKnowledgeBaseDetails(mods...).All(ctx, r.mysqlConn)
	return
}

func (r *customBlogBookRepository) GetMeta(
	ctx context.Context,
	cols model.M,
	withCount int,
	filter map[string]map[string][]any,
) (list []*model.BlogKnowledgeBaseMetum, count int64, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	var mods []qm.QueryMod
	var page int
	var pageSize int
	var selectCol string
	for k, v := range cols {
		switch k {
		case "page":
			if val, ok := v.(int64); ok && val > 1 {
				page = int(val)
			}
		case "pageSize":
			if val, ok := v.(int64); ok && val > 0 {
				pageSize = int(val)
			}
		case "orderBy":
			if val, ok := v.(string); ok && val != "" {
				mods = append(mods, qm.OrderBy(val))
			}
		case "select":
			if val, ok := v.(string); ok && val != "" {
				selectCol = val
			}
		}
	}

	if filter != nil {
		for key, opMap := range filter {
			switch key {
			case model.BlogKnowledgeBaseMetumColumns.MetaID:
				mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBaseMetumColumns.MetaID, opMap)...)
			case model.BlogKnowledgeBaseMetumColumns.KnowledgeBaseID:
				mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBaseMetumColumns.KnowledgeBaseID, opMap)...)
			case model.BlogKnowledgeBaseMetumColumns.MetaKey:
				mods = append(mods, modelx.GetStringMods(model.BlogKnowledgeBaseMetumColumns.MetaKey, opMap)...)
			case model.BlogKnowledgeBaseMetumColumns.MetaValue:
				mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBaseMetumColumns.MetaValue, opMap)...)
			}
		}
	}

	if withCount >= 0 {
		count, err = model.BlogKnowledgeBaseMeta(mods...).Count(ctx, r.mysqlConn)
		if err != nil {
			return
		}

		if withCount == 0 {
			return
		}
	}

	if pageSize > 0 {
		if page > 1 {
			mods = append(mods, qm.Offset(pageSize*(page-1)))
		}
		mods = append(mods, qm.Limit(pageSize))
	}

	var columns []string
	if selectCol != "" {
		if selectCol != "," {
			columns = strings.Split(selectCol, ",")
		}
		columns = append(columns, model.BlogKnowledgeBaseMetumColumns.MetaID)
		columns = append(columns, model.BlogKnowledgeBaseMetumColumns.KnowledgeBaseID)
	}
	if len(columns) > 0 {
		mods = append(mods, qm.Select(columns...))
	}

	list, err = model.BlogKnowledgeBaseMeta(mods...).All(ctx, r.mysqlConn)
	return
}
func (r *customBlogBookRepository) GetMedia(
	ctx context.Context,
	cols model.M,
	withCount int,
	filter map[string]map[string][]any,
) (list []*model.BlogAttachmentRelationship, count int64, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	var mods []qm.QueryMod
	var page int
	var pageSize int
	var selectCol string
	for k, v := range cols {
		switch k {
		case "page":
			if val, ok := v.(int64); ok && val > 1 {
				page = int(val)
			}
		case "pageSize":
			if val, ok := v.(int64); ok && val > 0 {
				pageSize = int(val)
			}
		case "orderBy":
			if val, ok := v.(string); ok && val != "" {
				mods = append(mods, qm.OrderBy(val))
			}
		case "select":
			if val, ok := v.(string); ok && val != "" {
				selectCol = val
			}
		}
	}

	if filter != nil {
		for key, opMap := range filter {
			switch key {
			case model.BlogAttachmentRelationshipColumns.AttachmentRelationshipID:
				mods = append(mods, modelx.GetIntMods(model.BlogAttachmentRelationshipColumns.AttachmentRelationshipID, opMap)...)
			case model.BlogAttachmentRelationshipColumns.ObjectID:
				mods = append(mods, modelx.GetIntMods(model.BlogAttachmentRelationshipColumns.ObjectID, opMap)...)
			case model.BlogAttachmentRelationshipColumns.ObjectType:
				mods = append(mods, modelx.GetIntMods(model.BlogAttachmentRelationshipColumns.ObjectType, opMap)...)
			case model.BlogAttachmentRelationshipColumns.AttachmentID:
				mods = append(mods, modelx.GetIntMods(model.BlogAttachmentRelationshipColumns.AttachmentID, opMap)...)
			case model.BlogAttachmentRelationshipColumns.AttachmentThumbnail:
				mods = append(mods, modelx.GetIntMods(model.BlogAttachmentRelationshipColumns.AttachmentThumbnail, opMap)...)
			case model.BlogAttachmentRelationshipColumns.AttachmentOrder:
				mods = append(mods, modelx.GetIntMods(model.BlogAttachmentRelationshipColumns.AttachmentOrder, opMap)...)
			}
		}
	}

	if withCount >= 0 {
		count, err = model.BlogAttachmentRelationships(mods...).Count(ctx, r.mysqlConn)
		if err != nil {
			return
		}

		if withCount == 0 {
			return
		}
	}

	if pageSize > 0 {
		if page > 1 {
			mods = append(mods, qm.Offset(pageSize*(page-1)))
		}
		mods = append(mods, qm.Limit(pageSize))
	}

	var columns []string
	if selectCol != "" {
		if selectCol != "," {
			columns = strings.Split(selectCol, ",")
		}
		columns = append(columns, model.BlogAttachmentRelationshipColumns.AttachmentRelationshipID)
		columns = append(columns, model.BlogAttachmentRelationshipColumns.ObjectID)
	}
	if len(columns) > 0 {
		mods = append(mods, qm.Select(columns...))
	}

	list, err = model.BlogAttachmentRelationships(mods...).All(ctx, r.mysqlConn)
	return
}

func (r *customBlogBookRepository) InsertMedia(ctx context.Context, media []*model.BlogAttachmentRelationship) (err error) {
	if err = r.Conn(); err != nil {
		return
	}

	if len(media) > 0 {
		for _, m := range media {
			err = m.Insert(ctx, r.mysqlConn, boil.Infer())
			if err != nil {
				return
			}
		}
	}

	return
}

func (r *customBlogBookRepository) GetRelationshipList(
	ctx context.Context,
	cols model.M,
	withCount int,
	filter map[string]map[string][]any,
) (list []*model.BlogKnowledgeBaseRelationship, count int64, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	var mods []qm.QueryMod
	var page int
	var pageSize int
	var offset int
	var limit int
	var selectCol string
	for k, v := range cols {
		switch k {
		case "page":
			if val, ok := v.(int64); ok && val > 1 {
				page = int(val)
			}
		case "pageSize":
			if val, ok := v.(int64); ok && val > 0 {
				pageSize = int(val)
			}
		case "offset":
			if val, ok := v.(int32); ok && val > 0 {
				offset = int(val)
			}
		case "limit":
			if val, ok := v.(int32); ok && val > 0 {
				limit = int(val)
			}
		case "orderBy":
			if val, ok := v.(string); ok && val != "" {
				mods = append(mods, qm.OrderBy(val))
			}
		case "select":
			if val, ok := v.(string); ok && val != "" {
				selectCol = val
			}
		}
	}

	if filter != nil {
		for key, opMap := range filter {
			switch key {
			case model.BlogKnowledgeBaseRelationshipColumns.EntryRelationshipID:
				mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBaseRelationshipColumns.EntryRelationshipID, opMap)...)
			case model.BlogKnowledgeBaseRelationshipColumns.FromEntryID:
				mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBaseRelationshipColumns.FromEntryID, opMap)...)
			case model.BlogKnowledgeBaseRelationshipColumns.FromSectionID:
				mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBaseRelationshipColumns.FromSectionID, opMap)...)
			case model.BlogKnowledgeBaseRelationshipColumns.ToEntryID:
				mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBaseRelationshipColumns.ToEntryID, opMap)...)
			case model.BlogKnowledgeBaseRelationshipColumns.ToSectionID:
				mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBaseRelationshipColumns.ToSectionID, opMap)...)
			case model.BlogKnowledgeBaseRelationshipColumns.ToEntryGroup:
				mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBaseRelationshipColumns.ToEntryGroup, opMap)...)
			case model.BlogKnowledgeBaseRelationshipColumns.ToEntryOrder:
				mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBaseRelationshipColumns.ToEntryOrder, opMap)...)
			}
		}
	}

	if withCount >= 0 {
		if withCount == 2 {
			var nextCount int64
			var previousCount int64
			subMods := make([]qm.QueryMod, len(mods), len(mods)+3)
			copy(subMods, mods)
			subMods = append(subMods, qm.Limit(1))
			subMods = append(subMods, qm.Select(model.BlogKnowledgeBaseRelationshipColumns.EntryRelationshipID))

			if offset >= 1 {
				subMods = append(subMods, qm.Offset(offset-1))
				previousList, previousErr := model.BlogKnowledgeBaseRelationships(subMods...).All(ctx, r.mysqlConn)
				if previousErr != nil {
					err = previousErr
					return
				}
				if len(previousList) > 0 {
					previousCount = 1
				}
			}
			if limit > 0 {
				subMods = append(subMods, qm.Offset(offset+limit))
				nextList, nextErr := model.BlogKnowledgeBaseRelationships(subMods...).All(ctx, r.mysqlConn)
				if nextErr != nil {
					err = nextErr
					return
				}
				if len(nextList) > 0 {
					nextCount = 1
				}
			}

			count = previousCount + nextCount*2
		} else {
			count, err = model.BlogKnowledgeBaseRelationships(mods...).Count(ctx, r.mysqlConn)
			if err != nil {
				return
			}

			if withCount == 0 {
				return
			}
		}
	}

	if pageSize > 0 {
		if page > 1 {
			mods = append(mods, qm.Offset(pageSize*(page-1)))
		}
		mods = append(mods, qm.Limit(pageSize))
	} else if limit > 0 || offset > 0 {
		if limit > 0 {
			mods = append(mods, qm.Limit(limit))
		}
		if offset > 0 {
			mods = append(mods, qm.Offset(offset))
		}
	}

	var columns []string
	if selectCol != "" {
		if selectCol != "," {
			columns = strings.Split(selectCol, ",")
		}
		columns = append(columns, model.BlogKnowledgeBaseRelationshipColumns.EntryRelationshipID)
	}
	if len(columns) > 0 {
		mods = append(mods, qm.Select(columns...))
	}

	list, err = model.BlogKnowledgeBaseRelationships(mods...).All(ctx, r.mysqlConn)
	return
}

func (r *customBlogBookRepository) IncreaseMeta(
	ctx context.Context,
	ids []int64,
	metaKey string,
	step int,
) (err error) {
	if err = r.Conn(); err != nil {
		return
	}

	if len(ids) > 0 {
		eids := make([]string, 0, len(ids))
		for _, eid := range ids {
			eids = append(eids, strconv.FormatInt(eid, 10))
		}
		var info RandomInfo
		err = queries.Raw(fmt.Sprintf(
			`update %s set %s=%s+%d where %s="%s" and %s in (%s)`,
			model.TableNames.BlogKnowledgeBaseMeta,
			model.BlogKnowledgeBaseMetumColumns.MetaValue,
			model.BlogKnowledgeBaseMetumColumns.MetaValue,
			step,
			model.BlogKnowledgeBaseMetumColumns.MetaKey,
			metaKey,
			model.BlogKnowledgeBaseMetumColumns.KnowledgeBaseID,
			strings.Join(eids, ","),
		)).Bind(ctx, r.mysqlConn, &info)

		if err == sql.ErrNoRows {
			return model.ErrNotFound
		}
	}

	return
}

func (r *customBlogBookRepository) DecreaseMeta(
	ctx context.Context,
	ids []int64,
	metaKey string,
	step int,
) (err error) {
	if err = r.Conn(); err != nil {
		return
	}

	if len(ids) > 0 {
		eids := make([]string, 0, len(ids))
		for _, eid := range ids {
			eids = append(eids, strconv.FormatInt(eid, 10))
		}
		var info RandomInfo
		err = queries.Raw(fmt.Sprintf(
			`update %s set %s=%s-%d where %s="%s" and %s in (%s)`,
			model.TableNames.BlogKnowledgeBaseMeta,
			model.BlogKnowledgeBaseMetumColumns.MetaValue,
			model.BlogKnowledgeBaseMetumColumns.MetaValue,
			step,
			model.BlogKnowledgeBaseMetumColumns.MetaKey,
			metaKey,
			model.BlogKnowledgeBaseMetumColumns.KnowledgeBaseID,
			strings.Join(eids, ","),
		)).Bind(ctx, r.mysqlConn, &info)

		if err == sql.ErrNoRows {
			return model.ErrNotFound
		}
	}

	return
}

func (r *customBlogBookRepository) InsertMeta(ctx context.Context, meta []*model.BlogKnowledgeBaseMetum) (err error) {
	if err = r.Conn(); err != nil {
		return
	}

	if len(meta) > 0 {
		for _, m := range meta {
			err = m.Insert(ctx, r.mysqlConn, boil.Infer())
			if err != nil {
				return
			}
		}
	}

	return
}

func (r *customBlogBookRepository) UpdateMetum(ctx context.Context, id uint64, cols model.M) (rowsAff int64, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	var mods []qm.QueryMod
	mods = append(mods, model.BlogKnowledgeBaseMetumWhere.MetaID.EQ(id))

	rowsAff, err = model.BlogKnowledgeBaseMeta(mods...).UpdateAll(ctx, r.mysqlConn, cols)
	return
}
